//!!!!!!!!!!!!!!!!!fence.i inst is not include in is_I_type yet
`include "common_def.v"
`include "decode_def.v" 
module MODULE_IDU (
	input									id_start_i,
	output								id_ready_o,
	output								id_valid_o,
	input									DEp_ready_i,
	//inst_key is a key for forward unit
	output	[3:0]					inst_key_o,
	//input inst from IFU
	input 	[31:0]				inst_i,
	//connect with regs
	output	[4:0]					addr_src1_o,
	output	[4:0]					addr_src2_o,
	output  [4:0]					addr_dst_o,
	output	[11:0]				addr_csr_o,
	output 								wen_o, 
	output								wen_csr_o,
	output								is_ecall_o,//pass to reg to write some regs
	output								is_mret_o,
	output								is_fencei_o,
	output								is_load_o,
	//connect with EXU
		//out to EXU to cal
	output	[`WIDTH-1:0]		imm_o,//all imm is expend to 64bit in IDU
		//keys to exu muxs
	output	[`OP_NUM-1:0]	alu_key_o,//choose which cal
	output	[1:0]					mul_sign_key_o,
	output	[`A_NUM-1:0]	alu_A_key_o,
	output	[`B_NUM-1:0]	alu_B_key_o,//choose src is imm or regs
	output 	[`SHAMT_NUM-1:0]shamt_key_o,
	output  							alu_result_key_o,
	output	[`RESULT_NUM-1:0]result_key_o,//choose what to write regs
	output	[`CSR_KEY_NUM-1:0]data_csr_key_o,//choose what to write csrcs
	output									csr_i_or_r_key_o,
	output	[`LOAD_NUM-1:0]load_data_key_o,
	output	[2:0]					ls_size_o,
	//connect with MEM
	output 	[7:0]					store_mask_o,	
	output  							read_en_o,
	output								write_en_o
);
assign id_ready_o = 1'b1 & DEp_ready_i;
assign id_valid_o = id_start_i;
//first leval class
wire is_inst;
wire is_I_type;
wire is_U_type;
wire is_J_type;
wire is_B_type;
wire is_R_type;
wire is_S_type;
assign is_I_type = is_cal_I |is_cal_w_I|is_jalr_I|is_load_I|is_sys_I|0;
assign is_U_type = is_lui_U|is_auipc_U|0;
assign is_J_type = is_jal_J|0;
assign is_B_type = is_b_B;
assign is_R_type = is_cal_w_R|is_cal_R;
assign is_S_type = is_store_S;

//second leval class
wire is_cal_I;
wire is_cal_R;
wire is_cal_w_R;
wire is_cal_w_I;
wire is_load_I;//include all load inst like lw, lb lh....
wire is_store_S;
wire is_b_B;
wire is_lui_U;
wire is_auipc_U;
wire is_jal_J;
wire is_jalr_I;
wire is_sys_I;
assign is_cal_I= (inst_i[6:0]==`CAL_I_OPCODE);
assign is_cal_R = (inst_i[6:0] == `CAL_R_OPCODE);
assign is_cal_w_I = (inst_i[6:0] == `CAL_W_I_OPCODE);
assign is_load_I = (inst_i[6:0] == `LOAD_OPCODE);
assign is_store_S = (inst_i[6:0] == `STORE_OPCODE);
assign is_b_B = (inst_i[6:0] == `B_OPCODE);
assign is_lui_U = (inst_i[6:0]==`LUI_U_OPCODE);
assign is_auipc_U = (inst_i[6:0] == `AUIPC_OPCODE);
assign is_jal_J = (inst_i[6:0] == `JAL_OPCODE);
assign is_jalr_I = (inst_i[6:0] == `JALR_OPCODE)&(inst_i[14:12] == `JALR_FUNCT3);
assign is_cal_w_R = (inst_i[6:0] == `CAL_W_R_OPCODE);
assign is_sys_I = inst_i[6:0]==`SYS_OPCODE;
assign is_ecall_o = inst_i[31:0] == `ECALL;
assign is_mret_o = inst_i[31:0] == `MRET;
assign is_fencei_o = (inst_i[6:0] == `FENCEI_OPCODE) & (inst_i[14:12] == `FENCEI_FUNCT3);

assign is_inst = is_I_type|is_U_type|is_J_type|is_B_type|is_R_type|is_S_type|is_ecall_o|is_mret_o|is_fencei_o;
//!signal to REGS
	//gen wen_o
wire is_csr;
wire is_csr_i;
assign is_csr = (is_sys_I&(inst_i[14:12]==`CSRRW_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRS_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRC_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRWI_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRSI_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRCI_FUNCT3));
assign is_csr_i = (is_sys_I&(inst_i[14:12] == `CSRRWI_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRSI_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRCI_FUNCT3));
assign wen_o = (~is_B_type)&(~is_S_type)&(~is_mret_o)&(~is_ecall_o)&(~is_fencei_o)&is_inst;
assign wen_csr_o = is_csr;
	//gen reg's address
assign addr_src1_o[4:0] = inst_i[19:15];
assign addr_src2_o[4:0] = inst_i[24:20];
assign addr_dst_o[4:0] = inst_i[11:7];
wire [1:0]	addr_csr_o_key;//key for choose addr_csr_o_key,01 for MPC,10 for MTVEC,default for csr
assign addr_csr_o_key[0] = is_mret_o;
assign addr_csr_o_key[1] = is_ecall_o;
MuxKeyWithDefault #(2,2,12) addr_csr_o_mux (addr_csr_o[11:0],addr_csr_o_key[1:0],inst_i[31:20],{
	2'b01,	`MPC,
	2'b10,	`MTVEC
});



//!signal to EXU
	//gen alu_reslut_key ,this key is set for w cal inst,choose the 64'b alu result or low 32'b and sign ex as real alu_result; 1 use sign ex 32'b
assign alu_result_key_o = is_cal_w_R|is_cal_w_I;
	//gen result_key_o choose result to send to dest reg,01 use pc+4 ,10 use date from csr default use alu_result, 
assign result_key_o[0] = is_J_type|is_jalr_I|0;
assign result_key_o[1] = wen_csr_o;
assign is_load_o = is_load_I|0; 
	//gen data_csr_key 001 just output src1_i or imm to csrs,010 output src1_i or imm |csr to csr,100 ~(src1_i or imm) & csr
assign data_csr_key_o[0] = (is_sys_I&(inst_i[14:12] == `CSRRW_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRWI_FUNCT3));
assign data_csr_key_o[1] = (is_sys_I&(inst_i[14:12] == `CSRRS_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRSI_FUNCT3));
assign data_csr_key_o[2] = (is_sys_I&(inst_i[14:12] == `CSRRC_FUNCT3))|(is_sys_I&(inst_i[14:12] == `CSRRCI_FUNCT3));
//csr_i_or_r_key_o 1 mean use imm;
assign csr_i_or_r_key_o = is_csr_i;
	//gen alu_key now is only add is used
		//bit 0 is add,bit 1 is sltiu
assign alu_key_o[0] = (is_cal_I & (inst_i[14:12]==`ADDI_FUNCT3))|(is_cal_w_R &(inst_i[14:12] == `ADDW_FUNCT3)&(inst_i[31:25] == `ADDW_FUNCT7))|(is_cal_w_I&(inst_i[14:12]==`ADDIW_FUNCT3)) |(is_cal_R&(inst_i[14:12]==`ADD_FUNCT3)&(inst_i[31:25] == `ADD_FUNCT7))|is_jalr_I|is_B_type| is_U_type|is_S_type| is_J_type|is_load_I|0; 
assign alu_key_o[1] = is_cal_I & (inst_i[14:12]==`SLTIU_FUNCT3)|(is_cal_R&(inst_i[14:12] == `SLTU_FUNCT3)&(inst_i[31:25] == `SLTU_FUNCT7));//usigned  A_i <B_i ?1 :0;
assign alu_key_o[2] = is_cal_w_R & (inst_i[14:12] == `SLLW_FUNCT3)&(inst_i[31:25] == `SLLW_FUNCT7)|(is_cal_I&(inst_i[14:12] == `SLLI_FUNCT3)&(inst_i[31:26]== `SLLI_FUNCT6))|(is_cal_w_I&(inst_i[14:12]== `SLLIW_FUNCT3)&(inst_i[31:25]==`SLLIW_FUNCT7))|(is_cal_R &(inst_i[14:12] ==`SLL_FUNCT3)&(inst_i[31:25] == `SLL_FUNCT7));//sll shift left logic
assign alu_key_o[3] = (is_cal_I &(inst_i[14:12] == `XORI_FUNCT3))|(is_cal_R&(inst_i[14:12]==`XOR_FUNCT3)&(inst_i[31:25]==`XOR_FUNCT7));//xor
assign alu_key_o[4] = (is_cal_I &(inst_i[14:12] == `ANDI_FUNCT3))|(is_cal_R&(inst_i[14:12] == `AND_FUNCT3)&(inst_i[31:25]==`AND_FUNCT7));//and
assign alu_key_o[5] = (is_cal_I &(inst_i[14:12]==`SRAI_FUNCT3)&(inst_i[31:26] == `SRAI_FUNCT6))|(is_cal_w_I&(inst_i[14:12]==`SRAIW_FUNCT3)&(inst_i[31:25]==`SRAIW_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SRAW_FUNCT3)&(inst_i[31:25]==`SRAW_FUNCT7))|(is_cal_R&(inst_i[14:12]==`SRA_FUNCT3)&(inst_i[31:25]==`SRA_FUNCT7));//sra shift right a
assign alu_key_o[6] = (is_cal_R &(inst_i[14:12]==`SUB_FUNCT3)&(inst_i[31:25] == `SUB_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SUBW_FUNCT3)&(inst_i[31:25] == `SUBW_FUNCT7));//save_for_sub
assign alu_key_o[7] = (is_cal_R &(inst_i[14:12] == `OR_FUNCT3)&(inst_i[31:25] == `OR_FUNCT7))|(is_cal_I&(inst_i[14:12]==`ORI_FUNCT3));
assign alu_key_o[8] = (is_cal_I &(inst_i[14:12]==`SRLI_FUNCT3)&(inst_i[31:26] == `SRLI_FUNCT6))|(is_cal_w_I&(inst_i[14:12]==`SRLIW_FUNCT3)&(inst_i[31:25]==`SRLIW_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SRLW_FUNCT3)&(inst_i[31:25]==`SRLW_FUNCT7))|(is_cal_R&(inst_i[14:12] == `SRL_FUNCT3)&(inst_i[31:25] == `SRL_FUNCT7));//sra shift right logic
assign alu_key_o[9] = (is_cal_w_R &(inst_i[14:12] == `MULW_FUNCT3)&(inst_i[31:25] == `MULW_FUNCT7))|(is_cal_R&(inst_i[14:12]==`MUL_FUNCT3)&(inst_i[31:25]==`MUL_FUNCT7));//MUL
assign alu_key_o[10] = (is_cal_w_R &(inst_i[14:12] == `DIVW_FUNCT3)&(inst_i[31:25] == `DIVW_FUNCT7))|(is_cal_R &(inst_i[14:12]==`DIV_FUNCT3)&(inst_i[31:25] == `DIV_FUNCT7));//DIV
assign alu_key_o[11] = (is_cal_w_R &(inst_i[14:12] == `REMW_FUNCT3)&(inst_i[31:25] == `REMW_FUNCT7))|(is_cal_R&(inst_i[14:12] == `REM_FUNCT3)&(inst_i[31:25] == `REM_FUNCT7));//REM
assign alu_key_o[12] = (is_cal_R &(inst_i[14:12] == `DIVU_FUNCT3)&(inst_i[31:25] == `DIVU_FUNCT7))|(is_cal_w_R&(inst_i[14:12] == `DIVUW_FUNCT3)&(inst_i[31:25] == `DIVUW_FUNCT7));//DIVU
assign alu_key_o[13] = (is_cal_R &(inst_i[14:12] == `REMU_FUNCT3)&(inst_i[31:25] == `REMU_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`REMUW_FUNCT3)&(inst_i[31:25]==`REMUW_FUNCT7));//REMU
assign alu_key_o[14] = (is_cal_R &(inst_i[14:12]==`SLT_FUNCT3)&(inst_i[31:25]==`SLT_FUNCT7))|(is_cal_I&(inst_i[14:12]==`SLTI_FUNCT3));//signed  A_i <B_i ?1 :0;
assign alu_key_o[15] = is_mulh|is_mulhu|is_mulhsu;//MUL_H
	//gen mul_sign_key_o
wire is_mulh;
wire is_mulhu;
wire is_mulhsu;
assign is_mulh = (is_cal_R &(inst_i[14:12] == `MULH_FUNCT3)&(inst_i[31:25] == `MULH_FUNCT7));
assign is_mulhu = (is_cal_R&(inst_i[14:12]==`MULHU_FUNCT3)&(inst_i[31:25]==`MULHU_FUNCT7));
assign is_mulhsu = (is_cal_R&(inst_i[14:12]==`MULHSU_FUNCT3)&(inst_i[31:25]==`MULHSU_FUNCT7));
assign mul_sign_key_o[0] = alu_key_o[9]|is_mulh|is_mulhsu;
assign mul_sign_key_o[1] = alu_key_o[9]|is_mulh;
	//gen alu_A_key_o, 0001 use src1,0010 use pc, 0100 use 0 ,1000 use low 32bit of src1 
	//1000 happened when some special cal_w happen like srlw and srliw, but it is also included in I type or R type,so when alu_A_key_o[3] == 1,set [0] == 0 to handle this situation
assign alu_A_key_o[0] = ((is_I_type&(~(is_cal_w_I&(inst_i[14:12]==`SRLIW_FUNCT3)&(inst_i[31:25]==`SRLIW_FUNCT7))))|(is_R_type&(~(is_cal_w_R&(inst_i[14:12]==`SRLW_FUNCT3)&(inst_i[31:25]==`SRLW_FUNCT7))))|is_S_type);
assign alu_A_key_o[1] = is_auipc_U|is_J_type|is_B_type|0;
assign alu_A_key_o[2] = is_lui_U|0;
assign alu_A_key_o[3] = (is_cal_w_I&(inst_i[14:12]==`SRLIW_FUNCT3)&(inst_i[31:25]==`SRLIW_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SRLW_FUNCT3)&(inst_i[31:25]==`SRLW_FUNCT7));
	//gen alu_B_key_o,  01 use imm 10 use src2  
assign alu_B_key_o[0]= is_I_type|is_U_type|is_J_type|is_B_type|is_S_type;
assign alu_B_key_o[1]= is_R_type;
genvar i;
generate
	for(i=1;i<`B_NUM;i++) begin
		assign alu_B_key_o[i] = 1'b0;
	end
endgenerate
	//gen shamt_key_o this mux choose the 5 or 6 low bit of B and send to the alu's B,default use the full 64'b of B
	//use 01 for 5'b,10 for 6'bit
assign shamt_key_o[0] = is_cal_w_R & (inst_i[14:12] == `SLLW_FUNCT3)&(inst_i[31:25] == `SLLW_FUNCT7)|(is_cal_w_I&(inst_i[14:12]== `SLLIW_FUNCT3)&(inst_i[31:25]==`SLLIW_FUNCT7))|(is_cal_w_I&(inst_i[14:12]==`SRAIW_FUNCT3)&(inst_i[31:25]==`SRAIW_FUNCT7))|(is_cal_w_I&(inst_i[14:12]==`SRLIW_FUNCT3)&(inst_i[31:25]==`SRLIW_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SRAW_FUNCT3)&(inst_i[31:25]==`SRAW_FUNCT7))|(is_cal_w_R&(inst_i[14:12]==`SRLW_FUNCT3)&(inst_i[31:25]==`SRLW_FUNCT7));
assign shamt_key_o[1] = (is_cal_I &(inst_i[14:12]==`SRAI_FUNCT3)&(inst_i[31:26] == `SRAI_FUNCT6))| (is_cal_I &(inst_i[14:12]==`SRLI_FUNCT3)&(inst_i[31:26] == `SRLI_FUNCT6))|(is_cal_I&(inst_i[14:12] == `SLLI_FUNCT3)&(inst_i[31:26]== `SLLI_FUNCT6))|(is_cal_R &(inst_i[14:12] ==`SLL_FUNCT3)&(inst_i[31:25] == `SLL_FUNCT7))|(is_cal_R&(inst_i[14:12] == `SRL_FUNCT3)&(inst_i[31:25] == `SRL_FUNCT7))|(is_cal_R&(inst_i[14:12]==`SRA_FUNCT3)&(inst_i[31:25]==`SRA_FUNCT7));
	//gen imm_o;
		//gen imm_key; I 00001 U 00010 
wire [`IMM_NUM-1:0] imm_key;
assign imm_key[0] = is_I_type;
assign imm_key[1] = is_U_type;
assign imm_key[2] = is_J_type;
assign imm_key[3] = is_B_type;
assign imm_key[4] = is_S_type;
		//gen imm	
wire [`WIDTH-1:0]	imm_I;
wire [`WIDTH-1:0] imm_U;
wire [`WIDTH-1:0]	imm_J;
wire [`WIDTH-1:0]	imm_B;
wire [`WIDTH-1:0]	imm_S;
assign imm_I[`WIDTH-1:0] = {{(`WIDTH-12){inst_i[31]}},inst_i[31:20]}; 
assign imm_U[`WIDTH-1:0] = {{(`WIDTH-32){inst_i[31]}},inst_i[31:12],{12{1'b0}}}; 
assign imm_J[`WIDTH-1:0] = {{(`WIDTH-20){inst_i[31]}},inst_i[19:12],inst_i[20],inst_i[30:21],1'b0};
assign imm_B[`WIDTH-1:0] = {{(`WIDTH-12){inst_i[31]}},inst_i[7],inst_i[30:25],inst_i[11:8],1'b0};
assign imm_S[`WIDTH-1:0] = {{(`WIDTH-12){inst_i[31]}},inst_i[31:25],inst_i[11:7]};
wire [`WIDTH-1:0] imm_csr;
assign imm_csr[`WIDTH-1:0] = {59'b0,inst_i[19:15]};

		//chose imm_o from imm
MuxKeyWithDefault #(`IMM_NUM,`IMM_NUM,`WIDTH) imm_mux (imm_o[`WIDTH-1:0],imm_key[`IMM_NUM-1:0],{`WIDTH{1'b0}},{
	5'b00001,is_csr_i ? imm_csr[`WIDTH-1:0] : imm_I[`WIDTH-1:0],
	5'b00010,imm_U[`WIDTH-1:0],
	5'b00100,imm_J[`WIDTH-1:0],
	5'b01000,imm_B[`WIDTH-1:0],
	5'b10000,imm_S[`WIDTH-1:0]
});

	//choose how to get data from 64bit data from mem
	//the first bit mean choose the low 32 bits
assign load_data_key_o[0] = is_load_I&(inst_i[14:12]==`LW_FUNCT3);//is lw
assign load_data_key_o[1] = is_load_I&(inst_i[14:12]==`LD_FUNCT3);
assign load_data_key_o[2] = is_load_I&(inst_i[14:12]==`LBU_FUNCT3);
assign load_data_key_o[3] = is_load_I&(inst_i[14:12]==`LH_FUNCT3);
assign load_data_key_o[4] = is_load_I&(inst_i[14:12]==`LHU_FUNCT3);
assign load_data_key_o[5] = is_load_I&(inst_i[14:12]==`LB_FUNCT3);
assign load_data_key_o[6] = is_load_I&(inst_i[14:12]==`LWU_FUNCT3);

//!signal to MEM_CTR 
	//gen the store mask;01 chose d_mask,10 chose w mask
wire	[`STORE_MASK_NUM-1:0]	store_mux_key;
assign store_mux_key[0] = is_S_type&(inst_i[14:12] == `SD_FUNCT3);
assign store_mux_key[1] = is_S_type&(inst_i[14:12] == `SW_FUNCT3);
assign store_mux_key[2] = is_S_type&(inst_i[14:12] == `SH_FUNCT3);
assign store_mux_key[3] = is_S_type&(inst_i[14:12] == `SB_FUNCT3);
wire	[`STORE_MASK_LEN-1:0]	store_mask_d;
wire	[`STORE_MASK_LEN-1:0]	store_mask_w;
wire	[`STORE_MASK_LEN-1:0]	store_mask_h;
wire	[`STORE_MASK_LEN-1:0]	store_mask_b;
assign store_mask_d[`STORE_MASK_LEN-1:0] = 8'hff;
assign store_mask_w[`STORE_MASK_LEN-1:0] = 8'h0f;
assign store_mask_h[`STORE_MASK_LEN-1:0] = 8'h03;
assign store_mask_b[`STORE_MASK_LEN-1:0] = 8'h01;
MuxKeyWithDefault #(`STORE_MASK_NUM,`STORE_MASK_NUM,`STORE_MASK_LEN) store_mask_mux(store_mask_o[`STORE_MASK_LEN-1:0],store_mux_key[`STORE_MASK_NUM-1:0],{`STORE_MASK_LEN{1'b0}},{
	4'b0001,	store_mask_d[`STORE_MASK_LEN-1:0],
	4'b0010,	store_mask_w[`STORE_MASK_LEN-1:0],
	4'b0100,  store_mask_h[`STORE_MASK_LEN-1:0],
	4'b1000,  store_mask_b[`STORE_MASK_LEN-1:0]
});
assign store_mask_d = 8'hff;
//axi_ls_size
wire [2:0] axi_load_size;
wire [2:0] axi_store_size;
MuxKeyWithDefault #(`STORE_MASK_NUM,`STORE_MASK_NUM,3) axi_store_size_mux(axi_store_size[2:0],store_mux_key[`STORE_MASK_NUM-1:0],3'b0,{
	4'b0001,	`AXI_SIZE_D,
	4'b0010,	`AXI_SIZE_W,
	4'b0100,  `AXI_SIZE_H,
	4'b1000,  `AXI_SIZE_B
});
MuxKeyWithDefault #(`LOAD_NUM,`LOAD_NUM,3) axi_load_size_mux(axi_load_size[2:0],load_data_key_o[`LOAD_NUM-1:0],3'b0,{
7'b000_0001, `AXI_SIZE_W,
7'b000_0010, `AXI_SIZE_D,
7'b000_0100, `AXI_SIZE_B,
7'b000_1000, `AXI_SIZE_H,
7'b001_0000, `AXI_SIZE_H,
7'b010_0000, `AXI_SIZE_B,
7'b100_0000, `AXI_SIZE_W
});
assign ls_size_o[2:0] = is_load_I ? axi_load_size[2:0]:is_store_S?axi_store_size[2:0]:3'b0;

	//decide when can we read mem
assign read_en_o = is_load_I;
	//decide when can write mem
assign write_en_o = is_store_S;

//inst_key_o
assign inst_key_o[3] = is_load_I;
assign inst_key_o[2] = wen_o;
assign inst_key_o[1] = is_R_type | (is_I_type&(~is_csr_i)) | is_S_type | is_B_type;
assign inst_key_o[0] = is_R_type | is_S_type | is_B_type;

// trap inst or privileged inst


//ebreak
wire soft_break;//delete
export "DPI-C" function EBREAK;//delete
function void EBREAK();//delete
				output bit soft_break;//delete
				soft_break = (inst_i == 32'h00100073);//delete
endfunction//delete
//delete
export "DPI-C" function FTRACE_INFO;//delete
function void FTRACE_INFO();//delete
				output bit is_jal;//delete
				output bit is_jalr;//delete
				output bit[4:0] dest; //delete
				output bit[4:0] rs1; 	//delete
				output bit[`WIDTH-1:0] imm;//delete
				is_jal = is_jal_J;//delete
				is_jalr = is_jalr_I;//delete
				dest[4:0] = addr_dst_o;//delete
				rs1 [4:0] = addr_src1_o;//delete
				imm = imm_o;//delete
endfunction//delete
endmodule
